//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.security.oauth2.server.authorization.web;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
import org.springframework.security.crypto.keygen.StringKeyGenerator;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationAttributeNames;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.TokenType;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization.Builder;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.token.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.token.OAuth2Tokens;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.UriComponentsBuilder;

public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
    public static final String DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize";
    private static final String PKCE_ERROR_URI = "https://tools.ietf.org/html/rfc7636#section-4.4.1";
    private final RegisteredClientRepository registeredClientRepository;
    private final OAuth2AuthorizationService authorizationService;
    private final RequestMatcher authorizationRequestMatcher;
    private final RequestMatcher userConsentMatcher;
    private final StringKeyGenerator codeGenerator;
    private final StringKeyGenerator stateGenerator;
    private final RedirectStrategy redirectStrategy;

    public OAuth2AuthorizationEndpointFilter(RegisteredClientRepository registeredClientRepository, OAuth2AuthorizationService authorizationService) {
        this(registeredClientRepository, authorizationService, "/oauth2/authorize");
    }

    public OAuth2AuthorizationEndpointFilter(RegisteredClientRepository registeredClientRepository, OAuth2AuthorizationService authorizationService, String authorizationEndpointUri) {
        this.codeGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);
        this.stateGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
        this.redirectStrategy = new DefaultRedirectStrategy();
        Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
        Assert.notNull(authorizationService, "authorizationService cannot be null");
        Assert.hasText(authorizationEndpointUri, "authorizationEndpointUri cannot be empty");
        this.registeredClientRepository = registeredClientRepository;
        this.authorizationService = authorizationService;
        this.authorizationRequestMatcher = new AntPathRequestMatcher(authorizationEndpointUri, HttpMethod.GET.name());
        this.userConsentMatcher = new AntPathRequestMatcher(authorizationEndpointUri, HttpMethod.POST.name());
    }

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (this.authorizationRequestMatcher.matches(request)) {
            this.processAuthorizationRequest(request, response, filterChain);
        } else if (this.userConsentMatcher.matches(request)) {
            this.processUserConsent(request, response);
        } else {
            filterChain.doFilter(request, response);
        }

    }

    private void processAuthorizationRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        OAuth2AuthorizationEndpointFilter.OAuth2AuthorizationRequestContext authorizationRequestContext = new OAuth2AuthorizationEndpointFilter.OAuth2AuthorizationRequestContext(request.getRequestURL().toString(), OAuth2EndpointUtils.getParameters(request));
        this.validateAuthorizationRequest(authorizationRequestContext);
        if (authorizationRequestContext.hasError()) {
            if (authorizationRequestContext.isRedirectOnError()) {
                this.sendErrorResponse(request, response, authorizationRequestContext.resolveRedirectUri(), authorizationRequestContext.getError(), authorizationRequestContext.getState());
            } else {
                this.sendErrorResponse(response, authorizationRequestContext.getError());
            }

        } else {
            Authentication principal = SecurityContextHolder.getContext().getAuthentication();
            if (!isPrincipalAuthenticated(principal)) {
                filterChain.doFilter(request, response);
            } else {
                RegisteredClient registeredClient = authorizationRequestContext.getRegisteredClient();
                OAuth2AuthorizationRequest authorizationRequest = authorizationRequestContext.buildAuthorizationRequest();
                Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient).principalName(principal.getName()).attribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST, authorizationRequest);
                if (registeredClient.getClientSettings().requireUserConsent()) {
                    String state = this.stateGenerator.generateKey();
                    OAuth2Authorization authorization = builder.attribute(OAuth2AuthorizationAttributeNames.STATE, state).build();
                    this.authorizationService.save(authorization);
                    OAuth2AuthorizationEndpointFilter.UserConsentPage.displayConsent(request, response, registeredClient, authorization);
                } else {
                    Instant issuedAt = Instant.now();
                    Instant expiresAt = issuedAt.plus(5L, ChronoUnit.MINUTES);
                    OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(this.codeGenerator.generateKey(), issuedAt, expiresAt);
                    OAuth2Authorization authorization = builder.tokens(OAuth2Tokens.builder().token(authorizationCode).build()).attribute(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES, authorizationRequest.getScopes()).build();
                    this.authorizationService.save(authorization);
                    this.sendAuthorizationResponse(request, response, authorizationRequestContext.resolveRedirectUri(), authorizationCode, authorizationRequest.getState());
                }

            }
        }
    }

    private void processUserConsent(HttpServletRequest request, HttpServletResponse response) throws IOException {
        OAuth2AuthorizationEndpointFilter.UserConsentRequestContext userConsentRequestContext = new OAuth2AuthorizationEndpointFilter.UserConsentRequestContext(request.getRequestURL().toString(), OAuth2EndpointUtils.getParameters(request));
        this.validateUserConsentRequest(userConsentRequestContext);
        if (userConsentRequestContext.hasError()) {
            if (userConsentRequestContext.isRedirectOnError()) {
                this.sendErrorResponse(request, response, userConsentRequestContext.resolveRedirectUri(), userConsentRequestContext.getError(), userConsentRequestContext.getState());
            } else {
                this.sendErrorResponse(response, userConsentRequestContext.getError());
            }

        } else if (!OAuth2AuthorizationEndpointFilter.UserConsentPage.isConsentApproved(request)) {
            this.authorizationService.remove(userConsentRequestContext.getAuthorization());
            OAuth2Error error = createError("access_denied", "client_id");
            this.sendErrorResponse(request, response, userConsentRequestContext.resolveRedirectUri(), error, userConsentRequestContext.getAuthorizationRequest().getState());
        } else {
            Instant issuedAt = Instant.now();
            Instant expiresAt = issuedAt.plus(5L, ChronoUnit.MINUTES);
            OAuth2AuthorizationCode authorizationCode = new OAuth2AuthorizationCode(this.codeGenerator.generateKey(), issuedAt, expiresAt);
            OAuth2Authorization authorization = OAuth2Authorization.from(userConsentRequestContext.getAuthorization()).tokens(OAuth2Tokens.builder().token(authorizationCode).build()).attributes((attrs) -> {
                attrs.remove(OAuth2AuthorizationAttributeNames.STATE);
                attrs.put(OAuth2AuthorizationAttributeNames.AUTHORIZED_SCOPES, userConsentRequestContext.getScopes());
            }).build();
            this.authorizationService.save(authorization);
            this.sendAuthorizationResponse(request, response, userConsentRequestContext.resolveRedirectUri(), authorizationCode, userConsentRequestContext.getAuthorizationRequest().getState());
        }
    }

    private void validateAuthorizationRequest(OAuth2AuthorizationEndpointFilter.OAuth2AuthorizationRequestContext authorizationRequestContext) {
        if (StringUtils.hasText(authorizationRequestContext.getClientId()) && ((List)authorizationRequestContext.getParameters().get("client_id")).size() == 1) {
            RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(authorizationRequestContext.getClientId());
            if (registeredClient == null) {
                authorizationRequestContext.setError(createError("invalid_request", "client_id"));
            } else if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
                authorizationRequestContext.setError(createError("unauthorized_client", "client_id"));
            } else {
                authorizationRequestContext.setRegisteredClient(registeredClient);
                if (StringUtils.hasText(authorizationRequestContext.getRedirectUri())) {
                    if (!registeredClient.getRedirectUris().contains(authorizationRequestContext.getRedirectUri()) || ((List)authorizationRequestContext.getParameters().get("redirect_uri")).size() != 1) {
                        authorizationRequestContext.setError(createError("invalid_request", "redirect_uri"));
                        return;
                    }
                } else if (registeredClient.getRedirectUris().size() != 1) {
                    authorizationRequestContext.setError(createError("invalid_request", "redirect_uri"));
                    return;
                }

                authorizationRequestContext.setRedirectOnError(true);
                if (StringUtils.hasText(authorizationRequestContext.getResponseType()) && ((List)authorizationRequestContext.getParameters().get("response_type")).size() == 1) {
                    if (!authorizationRequestContext.getResponseType().equals(OAuth2AuthorizationResponseType.CODE.getValue())) {
                        authorizationRequestContext.setError(createError("unsupported_response_type", "response_type"));
                    } else {
                        Set<String> requestedScopes = authorizationRequestContext.getScopes();
                        Set<String> allowedScopes = registeredClient.getScopes();
                        if (!requestedScopes.isEmpty() && !allowedScopes.containsAll(requestedScopes)) {
                            authorizationRequestContext.setError(createError("invalid_scope", "scope"));
                        } else {
                            String codeChallenge = (String)authorizationRequestContext.getParameters().getFirst("code_challenge");
                            if (StringUtils.hasText(codeChallenge)) {
                                if (((List)authorizationRequestContext.getParameters().get("code_challenge")).size() != 1) {
                                    authorizationRequestContext.setError(createError("invalid_request", "code_challenge", "https://tools.ietf.org/html/rfc7636#section-4.4.1"));
                                    return;
                                }

                                String codeChallengeMethod = (String)authorizationRequestContext.getParameters().getFirst("code_challenge_method");
                                if (StringUtils.hasText(codeChallengeMethod) && (((List)authorizationRequestContext.getParameters().get("code_challenge_method")).size() != 1 || !"S256".equals(codeChallengeMethod) && !"plain".equals(codeChallengeMethod))) {
                                    authorizationRequestContext.setError(createError("invalid_request", "code_challenge_method", "https://tools.ietf.org/html/rfc7636#section-4.4.1"));
                                    return;
                                }
                            } else if (registeredClient.getClientSettings().requireProofKey()) {
                                authorizationRequestContext.setError(createError("invalid_request", "code_challenge", "https://tools.ietf.org/html/rfc7636#section-4.4.1"));
                                return;
                            }

                        }
                    }
                } else {
                    authorizationRequestContext.setError(createError("invalid_request", "response_type"));
                }
            }
        } else {
            authorizationRequestContext.setError(createError("invalid_request", "client_id"));
        }
    }

    private void validateUserConsentRequest(OAuth2AuthorizationEndpointFilter.UserConsentRequestContext userConsentRequestContext) {
        if (StringUtils.hasText(userConsentRequestContext.getState()) && ((List)userConsentRequestContext.getParameters().get("state")).size() == 1) {
            OAuth2Authorization authorization = this.authorizationService.findByToken(userConsentRequestContext.getState(), new TokenType(OAuth2AuthorizationAttributeNames.STATE));
            if (authorization == null) {
                userConsentRequestContext.setError(createError("invalid_request", "state"));
            } else {
                userConsentRequestContext.setAuthorization(authorization);
                Authentication principal = SecurityContextHolder.getContext().getAuthentication();
                if (isPrincipalAuthenticated(principal) && principal.getName().equals(authorization.getPrincipalName())) {
                    if (StringUtils.hasText(userConsentRequestContext.getClientId()) && ((List)userConsentRequestContext.getParameters().get("client_id")).size() == 1) {
                        RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(userConsentRequestContext.getClientId());
                        if (registeredClient != null && registeredClient.getId().equals(authorization.getRegisteredClientId())) {
                            userConsentRequestContext.setRegisteredClient(registeredClient);
                            userConsentRequestContext.setRedirectOnError(true);
                            Set<String> requestedScopes = userConsentRequestContext.getAuthorizationRequest().getScopes();
                            Set<String> authorizedScopes = userConsentRequestContext.getScopes();
                            if (!authorizedScopes.isEmpty() && !requestedScopes.containsAll(authorizedScopes)) {
                                userConsentRequestContext.setError(createError("invalid_scope", "scope"));
                            }
                        } else {
                            userConsentRequestContext.setError(createError("invalid_request", "client_id"));
                        }
                    } else {
                        userConsentRequestContext.setError(createError("invalid_request", "client_id"));
                    }
                } else {
                    userConsentRequestContext.setError(createError("invalid_request", "state"));
                }
            }
        } else {
            userConsentRequestContext.setError(createError("invalid_request", "state"));
        }
    }

    private void sendAuthorizationResponse(HttpServletRequest request, HttpServletResponse response, String redirectUri, OAuth2AuthorizationCode authorizationCode, String state) throws IOException {
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(redirectUri).queryParam("code", new Object[]{authorizationCode.getTokenValue()});
        if (StringUtils.hasText(state)) {
            uriBuilder.queryParam("state", new Object[]{state});
        }

        this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
    }

    private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, String redirectUri, OAuth2Error error, String state) throws IOException {
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(redirectUri).queryParam("error", new Object[]{error.getErrorCode()});
        if (StringUtils.hasText(error.getDescription())) {
            uriBuilder.queryParam("error_description", new Object[]{error.getDescription()});
        }

        if (StringUtils.hasText(error.getUri())) {
            uriBuilder.queryParam("error_uri", new Object[]{error.getUri()});
        }

        if (StringUtils.hasText(state)) {
            uriBuilder.queryParam("state", new Object[]{state});
        }

        this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
    }

    private void sendErrorResponse(HttpServletResponse response, OAuth2Error error) throws IOException {
        response.sendError(HttpStatus.BAD_REQUEST.value(), error.toString());
    }

    private static OAuth2Error createError(String errorCode, String parameterName) {
        return createError(errorCode, parameterName, "https://tools.ietf.org/html/rfc6749#section-4.1.2.1");
    }

    private static OAuth2Error createError(String errorCode, String parameterName, String errorUri) {
        return new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri);
    }

    private static boolean isPrincipalAuthenticated(Authentication principal) {
        return principal != null && !AnonymousAuthenticationToken.class.isAssignableFrom(principal.getClass()) && principal.isAuthenticated();
    }

    private static class UserConsentPage {
        private static final MediaType TEXT_HTML_UTF8;
        private static final String CONSENT_ACTION_PARAMETER_NAME = "consent_action";
        private static final String CONSENT_ACTION_APPROVE = "approve";
        private static final String CONSENT_ACTION_CANCEL = "cancel";

        private UserConsentPage() {
        }

        private static void displayConsent(HttpServletRequest request, HttpServletResponse response, RegisteredClient registeredClient, OAuth2Authorization authorization) throws IOException {
            String consentPage = generateConsentPage(request, registeredClient, authorization);
            response.setContentType(TEXT_HTML_UTF8.toString());
            response.setContentLength(consentPage.getBytes(StandardCharsets.UTF_8).length);
            response.getWriter().write(consentPage);
        }

        private static boolean isConsentApproved(HttpServletRequest request) {
            return "approve".equalsIgnoreCase(request.getParameter("consent_action"));
        }

        private static boolean isConsentCancelled(HttpServletRequest request) {
            return "cancel".equalsIgnoreCase(request.getParameter("consent_action"));
        }

        private static String generateConsentPage(HttpServletRequest request, RegisteredClient registeredClient, OAuth2Authorization authorization) {
            OAuth2AuthorizationRequest authorizationRequest = (OAuth2AuthorizationRequest)authorization.getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
            String state = (String)authorization.getAttribute(OAuth2AuthorizationAttributeNames.STATE);
            StringBuilder builder = new StringBuilder();
            builder.append("<!DOCTYPE html>");
            builder.append("<html lang=\"en\">");
            builder.append("<head>");
            builder.append("    <meta charset=\"utf-8\">");
            builder.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">");
            builder.append("    <link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css\" integrity=\"sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z\" crossorigin=\"anonymous\">");
            builder.append("    <title>Consent required</title>");
            builder.append("</head>");
            builder.append("<body>");
            builder.append("<div class=\"container\">");
            builder.append("    <div class=\"py-5\">");
            builder.append("        <h1 class=\"text-center\">Consent required</h1>");
            builder.append("    </div>");
            builder.append("    <div class=\"row\">");
            builder.append("        <div class=\"col text-center\">");
            builder.append("            <p><span class=\"font-weight-bold text-primary\">" + registeredClient.getClientId() + "</span> wants to access your account <span class=\"font-weight-bold\">" + authorization.getPrincipalName() + "</span></p>");
            builder.append("        </div>");
            builder.append("    </div>");
            builder.append("    <div class=\"row pb-3\">");
            builder.append("        <div class=\"col text-center\">");
            builder.append("            <p>The following permissions are requested by the above app.<br/>Please review these and consent if you approve.</p>");
            builder.append("        </div>");
            builder.append("    </div>");
            builder.append("    <div class=\"row\">");
            builder.append("        <div class=\"col text-center\">");
            builder.append("            <form method=\"post\" action=\"" + request.getRequestURI() + "\">");
            builder.append("                <input type=\"hidden\" name=\"client_id\" value=\"" + registeredClient.getClientId() + "\">");
            builder.append("                <input type=\"hidden\" name=\"state\" value=\"" + state + "\">");
            Iterator var6 = authorizationRequest.getScopes().iterator();

            while(var6.hasNext()) {
                String scope = (String)var6.next();
                builder.append("                <div class=\"form-group form-check py-1\">");
                builder.append("                    <input class=\"form-check-input\" type=\"checkbox\" name=\"scope\" value=\"" + scope + "\" id=\"" + scope + "\" checked>");
                builder.append("                    <label class=\"form-check-label\" for=\"" + scope + "\">" + scope + "</label>");
                builder.append("                </div>");
            }

            builder.append("                <div class=\"form-group pt-3\">");
            builder.append("                    <button class=\"btn btn-primary btn-lg\" type=\"submit\" name=\"consent_action\" value=\"approve\">Submit Consent</button>");
            builder.append("                </div>");
            builder.append("                <div class=\"form-group\">");
            builder.append("                    <button class=\"btn btn-link regular\" type=\"submit\" name=\"consent_action\" value=\"cancel\">Cancel</button>");
            builder.append("                </div>");
            builder.append("            </form>");
            builder.append("        </div>");
            builder.append("    </div>");
            builder.append("    <div class=\"row pt-4\">");
            builder.append("        <div class=\"col text-center\">");
            builder.append("            <p><small>Your consent to provide access is required.<br/>If you do not approve, click Cancel, in which case no information will be shared with the app.</small></p>");
            builder.append("        </div>");
            builder.append("    </div>");
            builder.append("</div>");
            builder.append("</body>");
            builder.append("</html>");
            return builder.toString();
        }

        static {
            TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);
        }
    }

    private abstract static class AbstractRequestContext {
        private final String authorizationUri;
        private final MultiValueMap<String, String> parameters;
        private final String clientId;
        private final String state;
        private final Set<String> scopes;
        private RegisteredClient registeredClient;
        private OAuth2Error error;
        private boolean redirectOnError;

        protected AbstractRequestContext(String authorizationUri, MultiValueMap<String, String> parameters, String clientId, String state, Set<String> scopes) {
            this.authorizationUri = authorizationUri;
            this.parameters = parameters;
            this.clientId = clientId;
            this.state = state;
            this.scopes = scopes;
        }

        protected String getAuthorizationUri() {
            return this.authorizationUri;
        }

        protected MultiValueMap<String, String> getParameters() {
            return this.parameters;
        }

        protected String getClientId() {
            return this.clientId;
        }

        protected String getState() {
            return this.state;
        }

        protected Set<String> getScopes() {
            return this.scopes;
        }

        protected RegisteredClient getRegisteredClient() {
            return this.registeredClient;
        }

        protected void setRegisteredClient(RegisteredClient registeredClient) {
            this.registeredClient = registeredClient;
        }

        protected OAuth2Error getError() {
            return this.error;
        }

        protected void setError(OAuth2Error error) {
            this.error = error;
        }

        protected boolean hasError() {
            return this.getError() != null;
        }

        protected boolean isRedirectOnError() {
            return this.redirectOnError;
        }

        protected void setRedirectOnError(boolean redirectOnError) {
            this.redirectOnError = redirectOnError;
        }

        protected abstract String resolveRedirectUri();
    }

    private static class UserConsentRequestContext extends OAuth2AuthorizationEndpointFilter.AbstractRequestContext {
        private OAuth2Authorization authorization;

        private UserConsentRequestContext(String authorizationUri, MultiValueMap<String, String> parameters) {
            super(authorizationUri, parameters, (String)parameters.getFirst("client_id"), (String)parameters.getFirst("state"), extractScopes(parameters));
        }

        private static Set<String> extractScopes(MultiValueMap<String, String> parameters) {
            List<String> scope = (List)parameters.get("scope");
            return (Set)(!CollectionUtils.isEmpty(scope) ? new HashSet(scope) : Collections.emptySet());
        }

        private OAuth2Authorization getAuthorization() {
            return this.authorization;
        }

        private void setAuthorization(OAuth2Authorization authorization) {
            this.authorization = authorization;
        }

        protected String resolveRedirectUri() {
            OAuth2AuthorizationRequest authorizationRequest = this.getAuthorizationRequest();
            return StringUtils.hasText(authorizationRequest.getRedirectUri()) ? authorizationRequest.getRedirectUri() : (String)this.getRegisteredClient().getRedirectUris().iterator().next();
        }

        private OAuth2AuthorizationRequest getAuthorizationRequest() {
            return (OAuth2AuthorizationRequest)this.getAuthorization().getAttribute(OAuth2AuthorizationAttributeNames.AUTHORIZATION_REQUEST);
        }
    }

    private static class OAuth2AuthorizationRequestContext extends OAuth2AuthorizationEndpointFilter.AbstractRequestContext {
        private final String responseType;
        private final String redirectUri;

        private OAuth2AuthorizationRequestContext(String authorizationUri, MultiValueMap<String, String> parameters) {
            super(authorizationUri, parameters, (String)parameters.getFirst("client_id"), (String)parameters.getFirst("state"), extractScopes(parameters));
            this.responseType = (String)parameters.getFirst("response_type");
            this.redirectUri = (String)parameters.getFirst("redirect_uri");
        }

        private static Set<String> extractScopes(MultiValueMap<String, String> parameters) {
            String scope = (String)parameters.getFirst("scope");
            return (Set)(StringUtils.hasText(scope) ? new HashSet(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))) : Collections.emptySet());
        }

        private String getResponseType() {
            return this.responseType;
        }

        private String getRedirectUri() {
            return this.redirectUri;
        }

        protected String resolveRedirectUri() {
            return StringUtils.hasText(this.getRedirectUri()) ? this.getRedirectUri() : (String)this.getRegisteredClient().getRedirectUris().iterator().next();
        }

        private OAuth2AuthorizationRequest buildAuthorizationRequest() {
            return OAuth2AuthorizationRequest.authorizationCode().authorizationUri(this.getAuthorizationUri()).clientId(this.getClientId()).redirectUri(this.getRedirectUri()).scopes(this.getScopes()).state(this.getState()).additionalParameters((additionalParameters) -> {
                this.getParameters().entrySet().stream().filter((e) -> {
                    return !((String)e.getKey()).equals("response_type") && !((String)e.getKey()).equals("client_id") && !((String)e.getKey()).equals("redirect_uri") && !((String)e.getKey()).equals("scope") && !((String)e.getKey()).equals("state");
                }).forEach((e) -> {
                    additionalParameters.put(e.getKey(), ((List)e.getValue()).get(0));
                });
            }).build();
        }
    }
}
